import numpy as np
from dbthing import *


# 实用函数
def n_2_01(n:int):
    '''
    若数字大于0, 返回1, 等于0, 返回0
    :param n: 数字
    :return: 0或1
    '''
    if n==0:
        return 0
    else:
        return 1

def vec2str(vec)->str:
    '''
    把向量变成str, 方便放进mysql
    :param vec:  [[0.2],[0.8]]
    :return: "0.2 0.8"
    '''
    vec = vec.reshape(1,-1)
    vec = str(np.squeeze(vec))
    return vec[1:-1]

def str2vec(s):
    '''
    把mysql里面的str拉出来变成numpy向量
    :param s: "0.2 0.8"
    :return: [[0.2],[0.8]]
    '''
    n_list = list(map(lambda x:float(x), s.split(' ')))
    vec = np.array(n_list).reshape(-1,1)
    return vec

def seq2vec(seq:int):
    '''
    2进制数字变成0,1向量
    :param i: 11100b
    :return: [[0],[0],[0],[1]]
    '''
    vec = np.zeros((n_feature, 1))
    for i in range(n_feature):
        vec[i][0] = 1&seq
        seq = seq>>1
    return vec


# 全局数据
n_feature = 14
n_recommend = 5
prospect = 5
filter = 1
all_hobby = ["新闻", "财经", "科技", "体育", "娱乐", "教育", "交通", "游戏", "旅游", "生活", "音乐", "艺术", "美食", "学习"]


# 转换矩阵: 暂时随机生成
transition_matrix = np.random.random(size=(n_feature,2,2))


class Config:
    host = 'localhost'
    user = 'root'
    passwd = '100299'
    db = 'thing'

class RewardUser:
    def __init__(self, reward, username):
        self.reward = reward
        self.user = collection_user.find_one({'_id':username})

    def __lt__(self, other):
        return self.reward<other.reward

class User:
    def __init__(self):
        pass

    def __init__(self, username:str, password:str, history: list, history_reward:list,
                 hobby:list, friend_preference:list, transition_preferece:list):

        self.username = username
        self.password = password

        self.history = history # 2维list
        self.history_reward = history_reward # list

        self.hobby = np.array(hobby) # 1维array

        self.friend_preference = np.array(friend_preference)  # 1维
        self.transition_preference = np.array(transition_preferece)  # 14*2*2



    def friend_gain(self, friend:list)->float:
        '''
        计算朋友的单纯收益
        '''
        friend_vec = np.array(friend)
        return np.dot(friend_vec, self.friend_preference)


    def transition_vec(self, former_friend:list, latter_friend:list):
        former_friend = np.array(former_friend)
        latter_friend = np.array(latter_friend)
        vec = np.zeros((n_feature))
        for i in range(n_feature):
            vec[i] = transition_matrix[i][former_friend[i]][latter_friend[i]]
        return vec

    def trans_prefer_vec(self, former_friend:list, latter_friend:list):
        former_friend = np.array(former_friend)
        latter_friend = np.array(latter_friend)
        vec = np.zeros((n_feature))
        for i in range(n_feature):
            vec[i] = self.transition_preference[i][former_friend[i]][latter_friend[i]]
        return vec

    def transition_gain(self, former_friend:list, latter_friend:list)->int:
        '''
        计算 friend_i -> friend_j 这个转变带来的收益
        '''
        vec1 = self.transition_vec(former_friend, latter_friend)
        vec2 = self.trans_prefer_vec(former_friend, latter_friend)
        return np.dot(vec1, vec2)


    def history_transition_gain(self, new_friend:list):
        res = 0
        len_his = len(self.history)
        for idx, history_friend in enumerate(self.history):
            res += (1/pow(len_his-idx,2)) * self.transition_gain(history_friend, new_friend)
        return res


    def update(self, new_friend:list, reward:int):
        avg_his_reward = np.average(self.history_reward)
        signal = np.log(reward/avg_his_reward)

        k = len(self.history)

        gain_friend = self.friend_gain(new_friend)
        gain_transition = self.history_transition_gain(new_friend)

        scale_friend = gain_friend/(gain_friend+gain_transition)
        scale_transition = gain_transition/(gain_friend+gain_transition)

        self.friend_preference = (k/(k+1))*self.friend_preference + (1/(k+1))*new_friend*scale_friend*signal

        last_friend = self.history[-1]
        trans_vec = self.transition_vec(last_friend, new_friend)

        for i in range(n_feature):
            self.transition_preference[i][last_friend][new_friend] = \
                (k/(k+1))*self.transition_preference[i][last_friend][new_friend] \
                + (1/(k+1))*trans_vec[i]*scale_transition*signal


    def recommend(self):
        pass


    def show(self):
        print(self.username)
        print(self.password)
        print(self.history)
        print(self.history_reward)
        print(self.hobby)
        print(self.friend_preference)
        print(self.transition_preference)

    def show_preference(self):
        print(self.friend_preference)
        print(self.transition_preference)